/* 模型状态工具函数 */
// 第三方库
import * as THREE from "three";
import gsap from "gsap";
// 项目公用
import { color } from "./color";
import { degToRad } from "./angle";
import { layer, object3d } from "./index";
import Text from "../Text";
// 当前页面
import type {
  StateAspect,
  PartSetting,
  AffectingProperty,
  StateAspectSetting,
  TextStateSetting,
  SceneNodeData,
} from "../types";

// 图层设置
const layerPickable = 2;

// MARK: 主要函数 ---------------------------------------------------------------------------------

// 应用模型的所有状态设置
export function applyObjectStateSetting(
  object: THREE.Object3D | undefined,
  stateAspects: StateAspect[],
  stateSettings: StateAspectSetting[],
  showTextHelper = false
) {
  if (object == null) return;

  if (stateAspects.length > 0 && stateAspects.length != stateSettings.length) {
    console.error(
      "[applyNormalDefaultStateSetting] stateAspects 与 defaultStateSettings 没对齐"
    );
    return;
  }

  stateAspects.forEach((aspect, aspectIndex) => {
    const stateValue = stateSettings[aspectIndex].stateValue;
    applyAspectState(object, aspect, stateValue, showTextHelper);
  });

  trimRedundantTextParts(object, stateAspects);
}

// 应用模型的单方面状态设置
export function applyAspectState(
  object: THREE.Object3D | undefined,
  aspect: StateAspect,
  stateValue: string,
  showTextHelper = false
) {
  const aspectIsText = checkIsAspectText(aspect);
  if (!aspectIsText) {
    // 应用普通状态
    applyAspectNormalState(object, aspect, stateValue);
  } else {
    // 应用文字状态
    applyAspectTextState(object, aspect, stateValue, showTextHelper);
  }
}

// MARK: 设置 -------------------------------------------------------------------------------------

let fontUrl = "";
export function setFontUrl(fontUrl_: string) {
  fontUrl = fontUrl_;
}

// MARK: 普通状态 ---------------------------------------------------------------------------------

export function applyAspectNormalState(
  object: THREE.Object3D | undefined,
  aspect: StateAspect,
  targetStateValue: string
) {
  aspect.stateValues.forEach((stateValue) => {
    if (stateValue.name == targetStateValue) {
      stateValue?.partSettings.forEach((part) => {
        applyPartNormalState(
          object,
          part.targetPartName,
          part,
          aspect.affectingProperties
        );
      });
    }
  });
}

// 应用部件普通(非文字)设置
export function applyPartNormalState(
  object: THREE.Object3D | undefined,
  partName: string,
  setting: PartSetting,
  affectingProperties: AffectingProperty[]
) {
  if (object == null) return;

  const mesh = object3d.findMeshByName(object, partName);
  if (mesh == null) {
    console.warn(`在模型物体中找不到部件物体“${partName}”`);
  } else {
    // 颜色（材质）
    if (affectingProperties.includes("COLOR")) {
      const material = mesh.material as THREE.MeshStandardMaterial;
      if (material == null) {
        console.warn(`找到的部件物体没有材质，无法修改颜色“${partName}”`);
      } else {
        const r = setting.color[0] / 255;
        const g = setting.color[1] / 255;
        const b = setting.color[2] / 255;
        material.color.setRGB(r, g, b);
        material.color.convertSRGBToLinear();
      }
    }
    // 位置
    if (affectingProperties.includes("POSITION")) {
      const px = setting.position[0];
      const py = setting.position[1];
      const pz = setting.position[2];
      gsap.to(mesh.position, { x: px, y: py, z: pz });
    }
    // 旋转
    if (affectingProperties.includes("ROTATION")) {
      const rx = degToRad(setting.rotation[0]);
      const ry = degToRad(setting.rotation[1]);
      const rz = degToRad(setting.rotation[2]);
      gsap.to(mesh.rotation, { x: rx, y: ry, z: rz });
    }
    // 显隐
    if (affectingProperties.includes("VISIBLE")) {
      mesh.visible = setting.visible;
      // 不更改 pickable 图层的话，材质替换功能会有问题（因为有可能会拾取、替换到隐藏物体上）
      if (setting.visible) layer.enable(mesh, layerPickable);
      else layer.disable(mesh, layerPickable);
    }
  }
}

// MARK: 文字状态 ---------------------------------------------------------------------------------

// 应用方面的文字状态设置，没有时自动创建
export function applyAspectTextState(
  object: THREE.Object3D | undefined,
  stateAspect: StateAspect,
  textContent: string,
  showHelper = false
) {
  if (object == null) return;
  if (!checkIsAspectText(stateAspect)) return;

  // 查找 TextGroup，如果不存在，则自动创建
  let textGroup = object.children.find((child) => {
    const userData = child.userData as SceneNodeData;
    return userData.isTextGroup;
  });
  if (textGroup == null) {
    textGroup = new THREE.Group();
    textGroup.name = "TextGroup";
    const userData = textGroup.userData as SceneNodeData;
    userData.isTextGroup = true;
    object.add(textGroup);
  }

  // 寻找文字对象
  const textObject = textGroup!.children.find((textObject) => {
    const userData = textObject.userData as SceneNodeData;
    return userData.textObjectStateAspectName == stateAspect.aspectName;
  });
  // 读取文字设置
  const textSetting = stateAspect.textStateSetting!;
  // 补齐可选项
  if (textSetting.textAlign == null)
    textSetting.textAlign = Text.DEFAULT_TEXT_ALIGN; // 水平对齐
  if (textSetting.verticalAlign == null)
    textSetting.verticalAlign = Text.DEFAULT_VERTICAL_ALIGN; // 垂直对齐
  if (textSetting.areaSize == null) textSetting.areaSize = [1, 0.5]; // 区域大小
  if (textSetting.padding == null) textSetting.padding = Text.DEFAULT_PADDING; // 内边距
  // 转换格式
  const fontColor = color.rgbToHexNum(...textSetting.fontColor);

  // 根据是否存在，决定要创建还是同步
  if (textObject == null) {
    // 如果不存在，则自动创建文字对象
    const newTextObject = new Text(textContent, {
      showHelper,
      fontUrl,
      fontColor,
      fontSize: textSetting.fontSize,
      fontWeight: textSetting.fontWeight,
      position: textSetting.pivotPosition,
      width: textSetting.areaSize[0],
      height: textSetting.areaSize[1],
      paddingX: textSetting.padding[0],
      paddingY: textSetting.padding[1],
      textAlign: textSetting.textAlign,
      verticalAlign: textSetting.verticalAlign,
      backgroundUrl: textSetting.backgroundUrl,
    });
    newTextObject.name = `TextObject-${stateAspect.aspectName}`;
    const userData = newTextObject.userData as SceneNodeData;
    userData.textObjectStateAspectName = stateAspect.aspectName;
    textGroup!.add(newTextObject);
  } else {
    // 如果存在，则同步文字状态
    const text = textObject as Text;
    text.setContent(textContent);
    text.setFontSize(textSetting.fontSize);
    text.setFontColor(fontColor);
    text.setFontWeight(textSetting.fontWeight);
    text.setPosition(...textSetting.pivotPosition);
    text.setTextAlign(textSetting.textAlign);
    text.setVerticalAlign(textSetting.verticalAlign);
    text.setSize(...textSetting.areaSize);
    text.setPadding(textSetting.padding[0], textSetting.padding[1]);
    text.setBackgroundUrl(textSetting.backgroundUrl);
  }
}

// 修剪多余的文字部件（产生原因：在模型编辑界面，修改文字方面的名称）
function trimRedundantTextParts(
  object: THREE.Object3D | undefined,
  stateAspects: StateAspect[]
) {
  if (object == null) return;

  // 列出不多余的文字状态方面名称
  const allowedTextAspectNameMap: { [aspectName: string]: true } = {};
  stateAspects.forEach((aspect) => {
    if (checkIsAspectText(aspect))
      allowedTextAspectNameMap[aspect.aspectName] = true;
  });

  // 寻找文字对象容器
  const textGroup = object.children.find((child) => {
    const userData = child.userData as SceneNodeData;
    return userData.isTextGroup;
  });
  if (textGroup == null) return;

  // 寻找多余文字对象
  const trimmingTextObject: THREE.Object3D[] = [];
  textGroup.children.forEach((textObject) => {
    const userData = textObject.userData as SceneNodeData;
    const isRedundant =
      allowedTextAspectNameMap[userData.textObjectStateAspectName!] == null;
    if (isRedundant) trimmingTextObject.push(textObject);
  });

  // 移除多余文字对象
  trimmingTextObject.forEach((textObject) => textObject.removeFromParent());
}

// MARK: 数据状态 ---------------------------------------------------------------------------------

// 应用模型的数据状态
// 用法：applyObjectDataProp(door, [], {
//   switch: '1',
// })
export function applyObjectDataProp(
  object: THREE.Object3D | undefined,
  stateAspects: StateAspect[],
  dataPropMap: { [propName: string]: string }
) {
  if (object == null) return;

  stateAspects.forEach((aspect) => {
    // 如果状态方面未设置数据状态明，则跳过
    const aspectPropName = aspect.dataPropName;
    if (aspectPropName == null || aspectPropName == "") return;

    // 如果数据状态值为空，则跳过
    const aspectPropValue = dataPropMap[aspectPropName];
    if (aspectPropValue == null || aspectPropValue == "") return;

    // 查找数据状态值对应的状态，找不到则跳过
    const targetStateValue = aspect.stateValues.find((item) => {
      return item.dataPropValue == aspectPropValue;
    });
    if (targetStateValue == null) return;

    // 应用状态值
    const aspectIsText = checkIsAspectText(aspect);
    if (!aspectIsText) {
      // 应用普通状态
      targetStateValue.partSettings.forEach((part) => {
        applyPartNormalState(
          object,
          part.targetPartName,
          part,
          aspect.affectingProperties
        );
      });
    } else {
      // 应用文字状态
      applyAspectTextState(object, aspect, aspectPropValue);
    }
  });
}

// MARK: 辅助函数 ---------------------------------------------------------------------------------

// 检查状态方面是否是文字类型
export function checkIsAspectText(aspect: StateAspect) {
  return (
    aspect.affectingProperties.length == 1 &&
    aspect.affectingProperties[0] == "TEXT"
  );
}

// 使物体上的默认状态设置，与模型上的状态设置模板对齐（数量一致、类型一致）
export function alignObjectStateSetting(
  userData?: SceneNodeData,
  stateAspects?: StateAspect[]
) {
  if (userData == null || stateAspects == null) return;

  // 处理 userData.defaultStateSettings 为空
  if (userData.defaultStateSettings == null) userData.defaultStateSettings = [];

  // 处理数量不一致
  const defaultStateSettings = userData.defaultStateSettings;
  if (stateAspects.length != defaultStateSettings.length) {
    userData.defaultStateSettings = stateAspects.map((stateAspect) => {
      const defaultTextContent =
        stateAspect.textStateSetting?.defaultContent || "状态文字";
      const aspectIsText = checkIsAspectText(stateAspect);
      const stateValue = aspectIsText
        ? defaultTextContent
        : stateAspect.stateValues[0]?.name || "";
      return {
        aspectName: stateAspect.aspectName,
        stateValue,
      };
    });
  }

  // 处理类型不一致（stateValue 不存在）
  userData.defaultStateSettings.forEach((stateSetting, aspectIndex) => {
    const stateAspect = stateAspects[aspectIndex];
    const aspectIsText = checkIsAspectText(stateAspect);
    if (!aspectIsText) {
      const valueIndex = stateAspect.stateValues.findIndex((stateValue) => {
        return stateValue.name == stateSetting.stateValue;
      });
      if (valueIndex == -1) {
        stateSetting.stateValue = stateAspect.stateValues[0]?.name || "";
      }
    }
  });
}

export function createEmptyTextStateSetting(): TextStateSetting {
  return {
    pivotPosition: [0, 0.5, 0], // 轴心位置
    fontSize: 0.1, // 字号
    fontColor: [255, 255, 255], // 字色
    fontWeight: "REGULAR", // 字重
    defaultContent: "状态文字", // 默认文字内容
    textAlign: "center", // 水平对齐
    verticalAlign: "center", // 垂直对齐
    areaSize: [1, 0.5], // 区域大小
    padding: [0.05, 0.05], // 内边距设置
    backgroundUrl: "", // 背景图
  };
}
